import axios from 'axios';
import { ITarget } from '../..';
import { common, model, schema } from '../../../base';
import { FileInfo, IFileInfo } from '../../thing/fileinfo';

export enum Protocol {
  Silicon = 'https://api.siliconflow.cn',
  Orginone = 'http://a4313ed9-5aa9-f0b8-8a06-537bbbe3263a.ofalias.com:28000',
}

export type SupportedProtocols = keyof typeof Protocol;

export interface IModelManager extends common.Emitter {
  /** 所在组织 */
  target: ITarget;
  /** 注册模型 */
  registerModels: IModel[];
  /** 注册的大模型 */
  models: IModel[];
  /** 默认模型 */
  defaultModel: IModel;
  /** 创建模型 */
  createModel(model: schema.XModel): Promise<schema.XModel | undefined>;
  /** 获取模型 */
  getModels(protocol: SupportedProtocols, apiKey: string): Promise<model.BaseModel[]>;
  /** 加载模型 */
  loadContent(reload?: boolean): Promise<IModel[]>;
}

export class ModelManager extends common.Emitter implements IModelManager {
  constructor(target: ITarget) {
    super();
    this.key = common.generateUuid();
    this.target = target;
    this._subscribe();
    this.defaultModel = new BaseModel(
      {
        id: 'DeepSeek-R1-Distill-Qwen-7B-quantized.w8a8',
        code: 'DeepSeek-R1-Distill-Qwen-7B-quantized.w8a8',
        protocol: 'Orginone',
        apiKey: 'hdu123!',
      } as schema.XModel,
      this,
    );
  }

  get registerModels() {
    return [...this._models];
  }

  key: string;
  target: ITarget;
  _models: IModel[] = [];

  get models() {
    return [this.defaultModel, ...this._models];
  }

  loaded: boolean = false;
  defaultModel: IModel;

  async createModel(model: schema.XModel): Promise<schema.XModel | undefined> {
    model.typeName = '大语言模型';
    const result = await this.target.resource.modelColl.insert(model);
    if (result) {
      await this.target.resource.modelColl.notity({ operate: 'create', data: result });
    }
    return result;
  }

  async getModels(
    protocol: SupportedProtocols,
    apiKey: string,
  ): Promise<model.BaseModel[]> {
    switch (protocol) {
      case 'Silicon':
      case 'Orginone':
        try {
          const result = await axios.get(Protocol[protocol] + '/v1/models', {
            headers: { Authorization: `Bearer ${apiKey}` },
          });
          return result.data.data;
        } catch (error) {
          console.log(error);
          return [];
        }
    }
  }

  async loadContent(reload?: boolean): Promise<IModel[]> {
    if (reload || !this.loaded) {
      this.loaded = true;
      const models = await this.target.resource.modelColl.loadSpace({});
      this._models = models.map((item) => new BaseModel(item, this));
    }
    return this.models;
  }

  private _subscribe() {
    this.target.resource.modelColl.subscribe([this.key], (data) => {
      switch (data.operate) {
        case 'create':
          this._models.push(new BaseModel(data.data, this));
          break;
        case 'update':
          for (let index = 0; index < this._models.length; index++) {
            const model = this._models[index];
            if (model.id === data.data.id) {
              this._models[index] = new BaseModel(data.data, this);
              break;
            }
          }
          break;
        case 'remove':
          this._models = this._models.filter((item) => item.id !== data.data.id);
          break;
      }
      this.changCallback();
    });
  }
}

export interface BodyContent {
  content: string;
  reasoning: string;
}

export enum TokenStatus {
  /** 思考中，等待模型返回 */
  thinking = 1,
  /** 生成中 */
  generating,
  /** 已完成 */
  generated,
  /** 已终止 */
  aborted,
  /** 异常 */
  error,
}

interface GenTokensParams {
  content: string;
  message: model.ChatMessageType;
  abortCtrl?: AbortController;
  onStart?: () => Promise<void>;
  onEvent: (status: TokenStatus, body: BodyContent) => Promise<void>;
}

export interface IModel<T = schema.XModel> {
  /** 模型管理器 */
  modelManager: IModelManager;
  /** 主键 */
  id: string;
  /** 名称 */
  name: string;
  /** 编码 */
  code: string;
  /** 协议 */
  protocol: string;
  /** 元数据 */
  metadata: T;
  /** 支持深度思考 */
  deepThink: boolean;
  /** 支持联网搜索 */
  netSearch: boolean;
  /** 更新模型 */
  setMetadata(metadata: T): void;
  /** 生成 Tokens */
  genTokens(params: GenTokensParams): Promise<void>;
  /** 刪除模型 */
  delete(notify?: boolean): Promise<boolean>;
}

/** 硅基流动模型 */
export interface IBaseModel extends IFileInfo<schema.XModel>, IModel<schema.XModel> {
  /** 更新更新元信息 */
  update(metadata: schema.XModel): Promise<schema.XModel | undefined>;
}

export class BaseModel extends FileInfo<schema.XModel> implements IBaseModel {
  constructor(metadata: schema.XModel, modelManager: IModelManager) {
    super(metadata, modelManager.target.directory);
    this.modelManager = modelManager;
  }

  cacheFlag: string = 'model';
  modelManager: IModelManager;

  get protocol() {
    return this.metadata.protocol;
  }

  get deepThink() {
    return false;
  }

  get netSearch() {
    return false;
  }

  get coll() {
    return this.target.resource.modelColl;
  }

  async update(data: schema.XModel): Promise<schema.XModel | undefined> {
    const success = await this.coll.replace(data);
    if (success) {
      await this.coll.notity({ operate: 'update', data });
    }
    return success;
  }

  async delete(): Promise<boolean> {
    const success = await this.coll.remove(this.metadata);
    if (success) {
      await this.coll.notity({
        operate: 'remove',
        data: this.metadata,
      });
    }
    return success;
  }

  async genTokens(params: GenTokensParams): Promise<void> {
    try {
      let url: string = Protocol[this.metadata.protocol];
      let body: Record<string, any> = { model: this.code };
      switch (this.metadata.protocol) {
        case 'Silicon':
        case 'Orginone':
          url += '/v1/chat/completions';
          body = {
            ...body,
            stream: true,
            messages: [{ role: 'user', content: params.content }],
          };
          break;
      }
      const response = await fetch(url, {
        method: 'POST',
        headers: {
          Authorization: 'Bearer ' + this.metadata.apiKey,
          'Content-Type': 'application/json;charset=utf-8',
        },
        body: JSON.stringify(body),
      });

      if (!response.ok) {
        const errorData = await response.json().catch(() => ({}));
        throw new Error(
          `API请求失败: ${response.status} - ${
            errorData.error?.message || response.statusText
          }`,
        );
      }

      const reader = response.body?.getReader();
      if (reader) {
        await params.onStart?.();

        const decoder = new TextDecoder();
        let buffer = '';

        let bodyRef = { content: '', reasoning: '' };

        while (true) {
          if (params.abortCtrl?.signal?.aborted) {
            await reader.cancel();
            await params.onEvent?.(TokenStatus.aborted, bodyRef);
            return;
          }

          const { done, value } = await reader.read();
          if (done) break;

          buffer += decoder.decode(value);

          while (true) {
            const match = buffer.match(/^data:\s*(.*?)(\n\n|$)/);
            if (!match) break;

            const [full, message] = match;
            buffer = buffer.slice(full.length);

            if (message.trim() === '[DONE]') {
              await params.onEvent?.(TokenStatus.generated, bodyRef);
              return;
            }

            try {
              const response: model.SiliconFlowResponse = JSON.parse(message);
              for (const choice of response.choices) {
                const { content, reasoning_content } = choice.delta;
                bodyRef.content = bodyRef.content + (content ?? '');
                bodyRef.reasoning = bodyRef.reasoning + (reasoning_content ?? '');
              }
              await params.onEvent(TokenStatus.generating, bodyRef);
            } catch (e) {
              console.warn('Invalid JSON:', message);
            }
          }
        }
      }
    } catch (error) {
      if (error instanceof Error) {
        await params.onEvent(TokenStatus.generating, {
          content: error.message,
          reasoning: '',
        });
      }
    }
  }
}
